home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 November: Tool Chest / Dev.CD Nov 94.toast / Sample Code / MoreFiles 1.2.1 / MoreDesktopMgr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-07-20  |  29.5 KB  |  1,120 lines  |  [TEXT/KAHL]

  1. /*
  2. **    Apple Macintosh Developer Technical Support
  3. **
  4. **    A collection of useful high-level Desktop Manager routines.
  5. **    If the Desktop Manager isn't available, use the Desktop file
  6. **    for 'read' operations.
  7. **
  8. **    We do more because we can...
  9. **
  10. **    by Jim Luther and Nitin Ganatra, Apple Developer Technical Support
  11. **
  12. **    File:    MoreDesktopMgr.c
  13. **
  14. **    Copyright © 1994 Apple Computer, Inc.
  15. **    All rights reserved.
  16. **
  17. **    You may incorporate this sample code into your applications without
  18. **    restriction, though the sample code has been provided "AS IS" and the
  19. **    responsibility for its operation is 100% yours.  However, what you are
  20. **    not permitted to do is to redistribute the source as "DSC Sample Code"
  21. **    after having made changes. If you're going to re-distribute the source,
  22. **    we require that you make it clear in the source that the code was
  23. **    descended from Apple Sample Code, but that you've made changes.
  24. */
  25.  
  26. #ifndef __MOREDESKTOPMGR__
  27. #include "MoreDesktopMgr.h"
  28. #endif
  29.  
  30. /*****************************************************************************/
  31.  
  32. /*    Desktop file notes:
  33. **
  34. **    •    The Desktop file is owned by the Finder and is normally open by the
  35. **        Finder. That means that we only have read-only access to the Desktop
  36. **        file.
  37. **    •    Since the Resource Manager doesn't support shared access to resource
  38. **        files and we're using read-only access, we don't ever leave the
  39. **        Desktop file open.  We open a path to it, get the data we want out
  40. **        of it, and then close the open path. This is the only safe way to
  41. **        open a resource file with read-only access since some other program
  42. **        could have it open with write access.
  43. **    •    The bundle related resources in the Desktop file are normally
  44. **        purgable, so when we're looking through them, we don't bother to
  45. **        release resources we're done looking at - closing the resource file
  46. **        (which we always do) will release them.
  47. **    •    Since we can't assume the Desktop file is named "Desktop"
  48. **        (it probably is everywhere but France), we get the Desktop
  49. **        file's name by searching the volume's root directory for a file
  50. **        with fileType == 'FNDR' and creator == 'ERIK'. The only problem with
  51. **        this scheme is that someone could create another file with that type
  52. **        and creator in the root directory and we'd find the wrong file.
  53. **        The chances of this are very slim.
  54. */
  55.  
  56. /*****************************************************************************/
  57.  
  58. /* local defines */
  59.  
  60. #define kBNDLResType    'BNDL'
  61. #define kFREFResType    'FREF'
  62. #define kIconFamResType    'ICN#'
  63. #define    kFCMTResType    'FCMT'
  64. #define    kAPPLResType    'APPL'
  65.  
  66. /*****************************************************************************/
  67.  
  68. /* local data structures */
  69.  
  70. struct IDRec
  71. {
  72.     short        localID;
  73.     short        rsrcID;
  74. };
  75. typedef struct IDRec IDRec;
  76. typedef    IDRec *IDRecPtr;
  77.  
  78. struct BundleType
  79. {
  80.     OSType        type;            /* 'ICN#' or 'FREF' */
  81.     short        count;            /* number of IDRecs - 1 */
  82.     IDRec        idArray[1];
  83. };
  84. typedef struct BundleType BundleType;
  85. typedef BundleType *BundleTypePtr;
  86.  
  87. struct BNDLRec
  88. {
  89.     OSType        signature;        /* creator type signature */
  90.     short        versionID;        /* version - should always be 0 */
  91.     short        numTypes;        /* number of elements in typeArray - 1 */
  92.     BundleType    typeArray[1];
  93. };
  94. typedef struct BNDLRec BNDLRec;
  95. typedef BNDLRec **BNDLRecHandle;
  96.  
  97. struct FREFRec
  98. {
  99.     OSType        fileType;        /* file type */
  100.     short        iconID;            /* icon local ID */
  101.     Str255        fileName;        /* file name */
  102. };
  103. typedef struct FREFRec FREFRec;
  104. typedef FREFRec **FREFRecHandle;
  105.  
  106. struct APPLRec
  107. {
  108.     OSType        creator;        /* creator type signature */
  109.     long        parID;            /* parent directory ID */
  110.     Str255        applName;        /* application name */
  111. };
  112. typedef struct APPLRec APPLRec;
  113. typedef APPLRec *APPLRecPtr;
  114.  
  115. /*****************************************************************************/
  116.  
  117. /* static prototypes */
  118.  
  119. static    OSErr    GetDesktopFileName(short vRefNum,
  120.                                    Str255 desktopName);
  121.  
  122. static    OSErr    GetAPPLFromDesktopFile(StringPtr volName,
  123.                                        short vRefNum,
  124.                                        OSType creator,
  125.                                        short *applVRefNum,
  126.                                        long *applParID,
  127.                                        Str255 applName);
  128.  
  129. static    OSErr    FindBundleGivenCreator(OSType creator,
  130.                                        BNDLRecHandle *returnBndl);
  131.                                        
  132. static    OSErr    FindTypeInBundle(OSType typeToFind,
  133.                                  BNDLRecHandle theBndl,
  134.                                  BundleTypePtr *returnBundleType);
  135.                                          
  136. static    OSErr    GetLocalIDFromFREF(BundleTypePtr theBundleType,
  137.                                    OSType fileType,
  138.                                    short *iconLocalID);
  139.  
  140. static    OSErr    GetIconRsrcIDFromLocalID(BundleTypePtr theBundleType,
  141.                                          short iconLocalID,
  142.                                          short *iconRsrcID);
  143.  
  144. static    OSType    DTIconToResIcon(short iconType);
  145.  
  146. static    OSErr    GetIconFromDesktopFile(StringPtr volName,
  147.                                        short vRefNum,
  148.                                        short iconType,
  149.                                        OSType fileCreator,
  150.                                        OSType fileType,
  151.                                        Handle *iconHandle);
  152.  
  153. static    OSErr    GetCommentID(short vRefNum,
  154.                              long dirID,
  155.                              StringPtr name,
  156.                              short *commentID);
  157.  
  158. static    OSErr    GetCommentFromDesktopFile(short vRefNum,
  159.                                           long dirID,
  160.                                           StringPtr name,
  161.                                           Str255 comment);
  162.  
  163. /*****************************************************************************/
  164.  
  165. /*
  166. **    GetDesktopFileName
  167. **
  168. **    Get the name of the Desktop file.
  169. */
  170. static    OSErr    GetDesktopFileName(short vRefNum,
  171.                                    Str255 desktopName)
  172. {
  173.     OSErr            error;
  174.     HParamBlockRec    pb;
  175.     short            index;
  176.     Boolean            found = false;
  177.     
  178.     pb.fileParam.ioNamePtr = desktopName;
  179.     pb.fileParam.ioVRefNum = vRefNum;
  180.     pb.fileParam.ioFVersNum = 0;
  181.     index = 1;
  182.     do
  183.     {
  184.         pb.fileParam.ioDirID = fsRtDirID;
  185.         pb.fileParam.ioFDirIndex = index;
  186.         error = PBHGetFInfoSync(&pb);
  187.         if ( error == noErr )
  188.         {
  189.             if ( (pb.fileParam.ioFlFndrInfo.fdType == 'FNDR') &&
  190.                  (pb.fileParam.ioFlFndrInfo.fdCreator == 'ERIK') )
  191.             {
  192.                 found = true;
  193.             }
  194.         }
  195.         ++index;
  196.     } while ( (error == noErr) && !found );
  197.     
  198.     return ( error );
  199. }
  200.  
  201. /*****************************************************************************/
  202.  
  203. pascal    OSErr    DTOpen(StringPtr volName,
  204.                        short vRefNum,
  205.                        short *dtRefNum,
  206.                        Boolean *newDTDatabase)
  207. {
  208.     OSErr error;
  209.     GetVolParmsInfoBuffer volParmsInfo;
  210.     long infoSize;
  211.     DTPBRec pb;
  212.     
  213.     /* Check for volume Desktop Manager support before calling */
  214.     infoSize = sizeof(GetVolParmsInfoBuffer);
  215.     error = HGetVolParms(volName, vRefNum, &volParmsInfo, &infoSize);
  216.     if ( error == noErr )
  217.     {
  218.         if ( hasDesktopMgr(volParmsInfo) )
  219.         {
  220.             pb.ioNamePtr = volName;
  221.             pb.ioVRefNum = vRefNum;
  222.             error = PBDTOpenInform(&pb);
  223.             /* PBDTOpenInform informs us if the desktop was just created */
  224.             /* by leaving the low bit of ioTagInfo clear (0) */
  225.             *newDTDatabase = ((pb.ioTagInfo & 1L) == 0);
  226.             if ( error == paramErr )
  227.             {
  228.                 error = PBDTGetPath(&pb);
  229.                 /* PBDTGetPath doesn't tell us if the database is new */
  230.                 /* so assume it is not new */
  231.                 *newDTDatabase = false;
  232.             }
  233.             *dtRefNum = pb.ioDTRefNum;
  234.         }
  235.         else
  236.             error = paramErr;
  237.     }
  238.     return ( error );
  239. }
  240.  
  241. /*****************************************************************************/
  242.  
  243. /*
  244. **    GetAPPLFromDesktopFile
  245. **
  246. **    Get a application's location from the
  247. **    Desktop file's 'APPL' resources.
  248. */
  249. static    OSErr    GetAPPLFromDesktopFile(StringPtr volName,
  250.                                        short vRefNum,
  251.                                        OSType creator,
  252.                                        short *applVRefNum,
  253.                                        long *applParID,
  254.                                        Str255 applName)
  255. {
  256.     OSErr error;
  257.     short realVRefNum;
  258.     Str255 desktopName;
  259.     short savedResFile;
  260.     short dfRefNum;
  261.     Handle applResHandle;
  262.     Boolean foundCreator;
  263.     Ptr applPtr;
  264.     long applSize;
  265.     
  266.     error = DetermineVRefNum(volName, vRefNum, &realVRefNum);
  267.     if ( error == noErr )
  268.     {
  269.         error = GetDesktopFileName(realVRefNum, desktopName);
  270.         if ( error == noErr )
  271.         {
  272.             savedResFile = CurResFile();
  273.             /*
  274.             **    Open the 'Desktop' file in the root directory. (because
  275.             **    opening the resource file could preload unwanted resources,
  276.             **    bracket the call with SetResLoad(s))
  277.             */
  278.             SetResLoad(false);
  279.             dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm);
  280.             SetResLoad(true);
  281.             
  282.             if ( dfRefNum != -1)
  283.             {
  284.                 /* Get 'APPL' resource ID 0 */
  285.                 applResHandle = Get1Resource(kAPPLResType, 0);
  286.                 if ( applResHandle != NULL )
  287.                 {
  288.                     applSize = GetHandleSize((Handle)applResHandle);
  289.                     if ( applSize != 0 )    /* make sure the APPL resource isn't empty */
  290.                     {
  291.                         foundCreator = false;
  292.                         applPtr = *applResHandle;
  293.                         
  294.                         /* APPL's don't have a count so I have to use the size as the bounds */
  295.                         while ( (foundCreator == false) &&
  296.                                 (applPtr < (*applResHandle + applSize)) )
  297.                         {
  298.                             if ( ((APPLRecPtr)applPtr)->creator == creator )
  299.                             {
  300.                                 foundCreator = true;
  301.                             }
  302.                             else
  303.                             {
  304.                                 /* fun with pointer math... */
  305.                                 applPtr += sizeof(OSType) +
  306.                                            sizeof(long) +
  307.                                            ((APPLRecPtr)applPtr)->applName[0] + 1;
  308.                                 /* application mappings are word aligned within the resource */
  309.                                 if ( ((unsigned long)applPtr % 2) != 0 )
  310.                                     applPtr += 1;
  311.                             }
  312.                         }
  313.                         if ( foundCreator == true )
  314.                         {
  315.                             *applVRefNum = realVRefNum;
  316.                             *applParID = ((APPLRecPtr)applPtr)->parID;
  317.                             BlockMoveData(((APPLRecPtr)applPtr)->applName,
  318.                                           applName,
  319.                                           ((APPLRecPtr)applPtr)->applName[0] + 1);
  320.                             error = noErr;
  321.                         }
  322.                     }
  323.                     else
  324.                         error = afpItemNotFound;    /* no APPL mapping available */
  325.                 }
  326.                 else
  327.                     error = afpItemNotFound;    /* no APPL mapping available */
  328.                 
  329.                 /* restore the resource chain and close the Desktop file */
  330.                 UseResFile(savedResFile);
  331.                 CloseResFile(dfRefNum);
  332.             }
  333.             else
  334.                 error = afpItemNotFound;
  335.         }
  336.     }
  337.     return ( error );
  338. }
  339.  
  340. /*****************************************************************************/
  341.  
  342. pascal    OSErr    DTGetAPPL(StringPtr volName,
  343.                           short vRefNum,
  344.                           OSType creator,
  345.                           short *applVRefNum,
  346.                           long *applParID,
  347.                           Str255 applName)
  348. {
  349.     OSErr error;
  350.     UniversalFMPB pb;
  351.     short dtRefNum;
  352.     Boolean newDTDatabase;
  353.     short realVRefNum;
  354.     short index;
  355.     Boolean applFound;
  356.     FSSpec spec;
  357.     long actMatchCount;
  358.     
  359.     /* get the real vRefNum */
  360.     error = DetermineVRefNum(volName, vRefNum, &realVRefNum);
  361.     if ( error == noErr )
  362.     {
  363.         error = DTOpen(volName, vRefNum, &dtRefNum, &newDTDatabase);
  364.         if ( error == noErr )
  365.         {
  366.             if ( !newDTDatabase )
  367.             {
  368.                 index = 0;
  369.                 applFound = false;
  370.                 do
  371.                 {
  372.                     pb.dtPB.ioNamePtr = applName;
  373.                     pb.dtPB.ioDTRefNum = dtRefNum;
  374.                     pb.dtPB.ioIndex = index;
  375.                     pb.dtPB.ioFileCreator = creator;
  376.                     error = PBDTGetAPPLSync(&pb.dtPB);
  377.                     if ( error == noErr )
  378.                     {
  379.                         /* got a match - see if it is valid */
  380.                         
  381.                         *applVRefNum = realVRefNum; /* get the vRefNum now */
  382.                         *applParID = pb.dtPB.ioAPPLParID; /* get the parent ID now */
  383.     
  384.                         /* pb.hPB.fileParam.ioNamePtr is already set */
  385.                         pb.hPB.fileParam.ioVRefNum = realVRefNum;
  386.                         pb.hPB.fileParam.ioFVersNum = 0;
  387.                         pb.hPB.fileParam.ioDirID = *applParID;
  388.                         pb.hPB.fileParam.ioFDirIndex = 0;    /* use ioNamePtr and ioDirID */
  389.                         if ( PBHGetFInfoSync(&pb.hPB) == noErr )
  390.                         {
  391.                             if ( (pb.hPB.fileParam.ioFlFndrInfo.fdCreator == creator) &&
  392.                                  (pb.hPB.fileParam.ioFlFndrInfo.fdType == 'APPL') )
  393.                             {
  394.                                 applFound = true;
  395.                             }
  396.                         }
  397.                     }
  398.                     ++index;
  399.                 } while ( (error == noErr) && !applFound );
  400.                 if ( error == fnfErr )
  401.                     error = afpItemNotFound;
  402.             }
  403.             else
  404.                 /* Desktop database is empty (new), set error to try CatSearch */
  405.                 error = afpItemNotFound;
  406.         }
  407.         /* acceptable errors from Desktop Manager to continue are paramErr or afpItemNotFound */
  408.         if ( error == paramErr )
  409.         {
  410.             /* if paramErr, the volume didn't support the Desktop Manager */
  411.             /* try the Desktop file */
  412.             
  413.             error = GetAPPLFromDesktopFile(volName, vRefNum, creator,
  414.                                             applVRefNum, applParID, applName);
  415.             if ( error == noErr )
  416.             {
  417.                 /* got a match - see if it is valid */
  418.                 
  419.                 pb.hPB.fileParam.ioNamePtr = applName;
  420.                 pb.hPB.fileParam.ioVRefNum = *applVRefNum;
  421.                 pb.hPB.fileParam.ioFVersNum = 0;
  422.                 pb.hPB.fileParam.ioDirID = *applParID;
  423.                 pb.hPB.fileParam.ioFDirIndex = 0;    /* use ioNamePtr and ioDirID */
  424.                 if ( PBHGetFInfoSync(&pb.hPB) == noErr )
  425.                 {
  426.                     if ( (pb.hPB.fileParam.ioFlFndrInfo.fdCreator != creator) ||
  427.                          (pb.hPB.fileParam.ioFlFndrInfo.fdType != 'APPL') )
  428.                     {
  429.                         error = afpItemNotFound;
  430.                     }
  431.                 }
  432.                 else if ( error == fnfErr )
  433.                     error = afpItemNotFound;
  434.             }
  435.         }
  436.         /* acceptable error from DesktopFile code to continue is afpItemNotFound */
  437.         if ( error == afpItemNotFound )
  438.         {
  439.             /* Couldn't be found in the Desktop file either, try searching with CatSearch */
  440.             
  441.             error = CreatorTypeFileSearch(NULL, realVRefNum, creator, kAPPLResType, &spec, 1,
  442.                                             &actMatchCount, true);
  443.             if ( (error == noErr) || (error == eofErr) )
  444.             {
  445.                 if ( actMatchCount > 0 )
  446.                 {
  447.                     *applVRefNum = spec.vRefNum;
  448.                     *applParID = spec.parID;
  449.                     BlockMoveData(spec.name, applName, spec.name[0] + 1);
  450.                 }
  451.                 else
  452.                     error = afpItemNotFound;
  453.             }
  454.         }
  455.     }
  456.     return ( error );
  457. }
  458.  
  459. /*****************************************************************************/
  460.  
  461. pascal    OSErr    FSpDTGetAPPL(StringPtr volName,
  462.                              short vRefNum,
  463.                              OSType creator,
  464.                              FSSpec *spec)
  465. {
  466.     return ( DTGetAPPL(volName, vRefNum, creator,
  467.                         &(spec->vRefNum), &(spec->parID), spec->name) );
  468. }
  469.  
  470. /*****************************************************************************/
  471.  
  472. /*
  473. **    FindBundleGivenCreator
  474. **
  475. **    Search the current resource file for the 'BNDL' resource with the given
  476. **    creator and return a handle to it.
  477. */
  478. static    OSErr    FindBundleGivenCreator(OSType creator,
  479.                                        BNDLRecHandle *returnBndl)
  480. {
  481.     OSErr            error;
  482.     short            numOfBundles;
  483.     short            index;
  484.     BNDLRecHandle    theBndl;
  485.     
  486.     error = afpItemNotFound;    /* default to not found */
  487.     
  488.     /* Search each BNDL resource until we find the one with a matching creator. */
  489.     
  490.     numOfBundles = Count1Resources(kBNDLResType);
  491.     index = 1;
  492.     *returnBndl = NULL;
  493.     
  494.     while ( (index <= numOfBundles) && (*returnBndl == NULL) )
  495.     {
  496.         theBndl = (BNDLRecHandle)Get1IndResource(kBNDLResType, index);
  497.         
  498.         if ( theBndl != NULL )
  499.         {
  500.             if ( (*theBndl)->signature == creator )
  501.             {
  502.                 /* numTypes and typeArray->count will always be the actual count minus 1, */
  503.                 /* so 0 in both fields is valid. */
  504.                 if ( ((*theBndl)->numTypes >= 0) && ((*theBndl)->typeArray->count >= 0) )
  505.                 {
  506.                     /* got it */
  507.                     *returnBndl = theBndl;
  508.                     error = noErr;
  509.                 }
  510.             }
  511.         }    
  512.         
  513.         index ++;
  514.     }
  515.     
  516.     return ( error );
  517. }
  518.  
  519. /*****************************************************************************/
  520.  
  521. /*
  522. **    FindTypeInBundle
  523. **
  524. **    Given a Handle to a BNDL return a pointer to the desired type
  525. **    in it. If the type is not found, or if the type's count < 0,
  526. **    return afpItemNotFound.
  527. */
  528. static    OSErr    FindTypeInBundle(OSType typeToFind,
  529.                                  BNDLRecHandle theBndl,
  530.                                  BundleTypePtr *returnBundleType)
  531. {
  532.     OSErr            error;
  533.     short            index;
  534.     Ptr                ptrIterator;    /* use a Ptr so we can do ugly pointer math */
  535.     
  536.     error = afpItemNotFound;    /* default to not found */
  537.     
  538.     ptrIterator = (Ptr)((*theBndl)->typeArray);
  539.     index = 0;
  540.     *returnBundleType = NULL;
  541.  
  542.     while ( (index < ((*theBndl)->numTypes + 1)) &&
  543.             (*returnBundleType == NULL) )
  544.     {
  545.         if ( (((BundleTypePtr)ptrIterator)->type == typeToFind) &&
  546.              (((BundleTypePtr)ptrIterator)->count >= 0) )
  547.         {
  548.                 *returnBundleType = (BundleTypePtr)ptrIterator;
  549.                 error = noErr;
  550.         }
  551.         else
  552.         {
  553.             ptrIterator += ( sizeof(OSType) +
  554.                              sizeof(short) +
  555.                              ( sizeof(IDRec) * (((BundleTypePtr)ptrIterator)->count + 1) ) );
  556.             ++index;
  557.         }
  558.     }
  559.         
  560.     return ( error );
  561. }
  562.  
  563. /*****************************************************************************/
  564.  
  565. /*
  566. **    GetLocalIDFromFREF
  567. **
  568. **    Given a pointer to a 'FREF' BundleType record, load each 'FREF' resource
  569. **    looking for a matching fileType. If a matching fileType is found, return
  570. **    its icon local ID. If no match is found, return afpItemNotFound as the
  571. **    function result.
  572. */
  573. static    OSErr    GetLocalIDFromFREF(BundleTypePtr theBundleType,
  574.                                    OSType fileType,
  575.                                    short *iconLocalID)
  576. {
  577.     OSErr            error;
  578.     short            index;
  579.     IDRecPtr        idIterator;
  580.     FREFRecHandle    theFref;
  581.     
  582.     error = afpItemNotFound;    /* default to not found */
  583.     
  584.     /* For each localID in this type, get the FREF resource looking for fileType */
  585.     index = 0;
  586.     idIterator = &theBundleType->idArray[0];
  587.     *iconLocalID = 0;
  588.     
  589.     while ( (index <= (theBundleType->count + 1)) && (*iconLocalID == 0) )
  590.     {
  591.         theFref = (FREFRecHandle)Get1Resource(kFREFResType, idIterator->rsrcID);
  592.         if ( theFref != NULL )
  593.         {
  594.             if ( (*theFref)->fileType == fileType )
  595.             {
  596.                 *iconLocalID = (*theFref)->iconID;
  597.                 error = noErr;
  598.             }
  599.         }
  600.         
  601.         ++idIterator;
  602.         ++index;
  603.     }
  604.     
  605.     return ( error );
  606. }
  607.  
  608. /*****************************************************************************/
  609.  
  610. /*
  611. **    GetIconRsrcIDFromLocalID
  612. **
  613. **    Given a pointer to a 'ICN#' BundleType record, look for the IDRec with
  614. **    the localID that matches iconLocalID. If a matching IDRec is found,
  615. **    return the IDRec's rsrcID field value. If no match is found, return
  616. **    afpItemNotFound as the function result.
  617. */
  618. static    OSErr    GetIconRsrcIDFromLocalID(BundleTypePtr theBundleType,
  619.                                          short iconLocalID,
  620.                                          short *iconRsrcID)
  621. {
  622.     OSErr        error;
  623.     short        index;
  624.     IDRecPtr    idIterator;
  625.     
  626.     error = afpItemNotFound;    /* default to not found */
  627.     
  628.     /* Find the rsrcID of the icon family type, given the localID */
  629.     index = 0;
  630.     idIterator = &theBundleType->idArray[0];
  631.     *iconRsrcID = 0;
  632.     
  633.     while ( (index <= (theBundleType->count+1)) && (*iconRsrcID == 0) )
  634.     {
  635.         if ( idIterator->localID == iconLocalID )
  636.         {
  637.             *iconRsrcID = idIterator->rsrcID;
  638.             error = noErr;
  639.         }
  640.         
  641.         idIterator ++;
  642.         index ++;
  643.     }
  644.     
  645.     return ( error );
  646. }
  647.  
  648. /*****************************************************************************/
  649.  
  650. /*
  651. **    DTIconToResIcon
  652. **
  653. **    Map a Desktop Manager icon type to the corresponding resource type.
  654. **    Return (OSType)0 if there is no corresponding resource type.
  655. */
  656. static    OSType    DTIconToResIcon(short iconType)
  657. {
  658.     OSType    resType;
  659.     
  660.     switch ( iconType )
  661.     {
  662.         case kLargeIcon:
  663.             resType = large1BitMask;
  664.             break;
  665.         case kLarge4BitIcon:
  666.             resType = large4BitData;
  667.             break;
  668.         case kLarge8BitIcon:
  669.             resType = large8BitData;
  670.             break;
  671.         case kSmallIcon:
  672.             resType = small1BitMask;
  673.             break;
  674.         case kSmall4BitIcon:
  675.             resType = small4BitData;
  676.             break;
  677.         case kSmall8BitIcon:
  678.             resType = small8BitData;
  679.             break;
  680.         default:
  681.             resType = (OSType)0;
  682.             break;
  683.     }
  684.     
  685.     return ( resType );
  686. }
  687.  
  688. /*****************************************************************************/
  689.  
  690. /*
  691. /*    GetIconFromDesktopFile
  692. **
  693. **    INPUT a pointer to a non-existent Handle, because we'll allocate one
  694. **
  695. **    search each BNDL resource for the right fileCreator and once we get it
  696. **        find the 'FREF' type in BNDL
  697. **        for each localID in the type, open the FREF resource
  698. **            if the FREF is the desired fileType
  699. **                get its icon localID
  700. **                get the ICN# type in BNDL
  701. **                get the icon resource number from the icon localID
  702. **                get the icon resource type from the desktop mgr's iconType
  703. **                get the icon of that type and number
  704. */
  705. static    OSErr    GetIconFromDesktopFile(StringPtr volName,
  706.                                        short vRefNum,
  707.                                        short iconType,
  708.                                        OSType fileCreator,
  709.                                        OSType fileType,
  710.                                        Handle *iconHandle)
  711. {
  712.     OSErr            error;
  713.     short            realVRefNum;
  714.     Str255            desktopName;
  715.     short            savedResFile;
  716.     short            dfRefNum;
  717.     BNDLRecHandle    theBndl = NULL;
  718.     BundleTypePtr    theBundleType;
  719.     short            iconLocalID;
  720.     short            iconRsrcID;
  721.     OSType            iconRsrcType;
  722.     Handle            returnIconHandle;    
  723.     char            bndlState;
  724.     
  725.     *iconHandle = NULL;
  726.     
  727.     error = DetermineVRefNum(volName, vRefNum, &realVRefNum);
  728.     if ( error == noErr )
  729.     {
  730.         error = GetDesktopFileName(realVRefNum, desktopName);
  731.         if ( error == noErr )
  732.         {
  733.             savedResFile = CurResFile();
  734.         
  735.             /*
  736.             **    Open the 'Desktop' file in the root directory. (because
  737.             **    opening the resource file could preload unwanted resources,
  738.             **    bracket the call with SetResLoad(s))
  739.             */
  740.             SetResLoad(false);
  741.             dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm);
  742.             SetResLoad(true);
  743.         
  744.             if ( dfRefNum != -1 )
  745.             {
  746.                 /*
  747.                 **    Find the BNDL resource with the specified creator.
  748.                 */
  749.                 error = FindBundleGivenCreator(fileCreator, &theBndl);
  750.                 if ( error == noErr )
  751.                 {
  752.                     /* Lock the BNDL resource so it won't be purged when other resources are loaded */
  753.                     bndlState = HGetState((Handle)theBndl);
  754.                     HLock((Handle)theBndl);
  755.                     
  756.                     /* Find the 'FREF' BundleType record in the BNDL resource. */
  757.                     error = FindTypeInBundle(kFREFResType, theBndl, &theBundleType);
  758.                     if ( error == noErr )
  759.                     {
  760.                         /* Find the local ID in the 'FREF' resource with the specified fileType */
  761.                         error = GetLocalIDFromFREF(theBundleType, fileType, &iconLocalID);
  762.                         if ( error == noErr )
  763.                         {
  764.                             /* Find the 'ICN#' BundleType record in the BNDL resource. */
  765.                             error = FindTypeInBundle(kIconFamResType, theBndl, &theBundleType);
  766.                             if ( error == noErr )
  767.                             {
  768.                                 /* Find the icon's resource ID in the 'ICN#' BundleType record */
  769.                                 error = GetIconRsrcIDFromLocalID(theBundleType, iconLocalID, &iconRsrcID);
  770.                                 if ( error == noErr )
  771.                                 {
  772.                                     /* Map Desktop Manager icon type to resource type */
  773.                                     iconRsrcType = DTIconToResIcon(iconType);
  774.                                     
  775.                                     if ( iconRsrcType != (OSType)0 )
  776.                                     {
  777.                                         /* Load the icon */
  778.                                         returnIconHandle = Get1Resource(iconRsrcType, iconRsrcID);
  779.                                         if ( returnIconHandle != NULL )
  780.                                         {
  781.                                             /* Copy the resource handle, and return the copy */
  782.                                             HandToHand(&returnIconHandle);
  783.                                             if ( MemError() == noErr )
  784.                                                 *iconHandle = returnIconHandle;
  785.                                             else
  786.                                                 error = afpItemNotFound;
  787.                                         }
  788.                                         else
  789.                                             error = afpItemNotFound;
  790.                                     }
  791.                                 }
  792.                             }
  793.                         }
  794.                     }
  795.                     /* Restore the state of the BNDL resource */ 
  796.                     HSetState((Handle)theBndl, bndlState);
  797.                 }
  798.                 /* Restore the resource chain and close the Desktop file */
  799.                 UseResFile(savedResFile);
  800.                 CloseResFile(dfRefNum);
  801.             }
  802.             else
  803.                 error = ResError(); /* could not open Desktop file */
  804.         }
  805.     }
  806.     
  807.     return ( error );
  808. }
  809.  
  810. /*****************************************************************************/
  811.  
  812. pascal    OSErr    DTGetIcon(StringPtr volName,
  813.                           short vRefNum,
  814.                           short iconType,
  815.                           OSType fileCreator,
  816.                           OSType fileType,
  817.                           Handle *iconHandle)
  818. {
  819.     OSErr error;
  820.     DTPBRec pb;
  821.     short dtRefNum;
  822.     Boolean newDTDatabase;
  823.     Size bufferSize;
  824.     
  825.     error = DTOpen(volName, vRefNum, &dtRefNum, &newDTDatabase);
  826.     if ( error == noErr )
  827.     {
  828.         /* there was a desktop database and it's now open */
  829.         
  830.         if ( !newDTDatabase )    /* don't bother to look in a new (empty) database */
  831.         {
  832.             /* get the buffer size for the requested icon type */
  833.             switch ( iconType )
  834.             {
  835.                 case kLargeIcon:
  836.                     bufferSize = kLargeIconSize;
  837.                     break;
  838.                 case kLarge4BitIcon:
  839.                     bufferSize = kLarge4BitIconSize;
  840.                     break;
  841.                 case kLarge8BitIcon:
  842.                     bufferSize = kLarge8BitIconSize;
  843.                     break;
  844.                 case kSmallIcon:
  845.                     bufferSize = kSmallIconSize;
  846.                     break;
  847.                 case kSmall4BitIcon:
  848.                     bufferSize = kSmall4BitIconSize;
  849.                     break;
  850.                 case kSmall8BitIcon:
  851.                     bufferSize = kSmall8BitIconSize;
  852.                     break;
  853.                 default:
  854.                     iconType = 0;
  855.                     bufferSize = 0;
  856.                     break;
  857.             }
  858.             if ( bufferSize != 0 )
  859.             {
  860.                 *iconHandle = NewHandle(bufferSize);
  861.                 if ( *iconHandle != NULL )
  862.                 {
  863.                     HLock(*iconHandle);
  864.         
  865.                     pb.ioDTRefNum = dtRefNum;
  866.                     pb.ioTagInfo = 0;
  867.                     pb.ioDTBuffer = **iconHandle;
  868.                     pb.ioDTReqCount = bufferSize;
  869.                     pb.ioIconType = iconType;
  870.                     pb.ioFileCreator = fileCreator;
  871.                     pb.ioFileType = fileType;
  872.                     error = PBDTGetIconSync(&pb);
  873.     
  874.                     HUnlock(*iconHandle);
  875.                     
  876.                     if ( error != noErr )
  877.                         DisposeHandle(*iconHandle);    /* dispose of the allocated memory */
  878.                 }
  879.                 else
  880.                     error = memFullErr;    /* handle could not be allocated */
  881.             }
  882.             else
  883.                 error = paramErr;    /* unknown icon type requested */
  884.         }
  885.         else
  886.             error = afpItemNotFound;    /* the desktop database was empty - nothing to return */
  887.     }
  888.     else
  889.     {
  890.         /* There is no desktop database - try the Desktop file */
  891.         
  892.         error = GetIconFromDesktopFile(volName, vRefNum, iconType,
  893.                                         fileCreator, fileType, iconHandle);
  894.     }
  895.     
  896.     return ( error );
  897. }
  898.  
  899. /*****************************************************************************/
  900.  
  901. pascal    OSErr    DTSetComment(short vRefNum,
  902.                              long dirID,
  903.                              StringPtr name,
  904.                              ConstStr255Param comment)
  905. {
  906.     DTPBRec pb;
  907.     OSErr error;
  908.     short dtRefNum;
  909.     Boolean newDTDatabase;
  910.  
  911.     error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
  912.     if ( error == noErr )
  913.     {
  914.         pb.ioDTRefNum = dtRefNum;
  915.         pb.ioNamePtr = name;
  916.         pb.ioDirID = dirID;
  917.         pb.ioDTBuffer = (Ptr)&comment[1];
  918.         /* Truncate the comment to 200 characters just in case */
  919.         /* some file system doesn't range check */
  920.         if ( comment[0] <= 200 )
  921.             pb.ioDTReqCount = comment[0];
  922.         else
  923.             pb.ioDTReqCount = 200;
  924.         error = PBDTSetCommentSync(&pb);
  925.     }
  926.     return (error);
  927. }
  928.  
  929. /*****************************************************************************/
  930.  
  931. pascal    OSErr    FSpDTSetComment(const FSSpec *spec,
  932.                               ConstStr255Param comment)
  933. {
  934.     return (DTSetComment(spec->vRefNum, spec->parID, (StringPtr)spec->name, comment));
  935. }
  936.  
  937. /*****************************************************************************/
  938.  
  939. /*
  940. **    GetCommentID
  941. **
  942. **    Get the comment ID number for the Desktop file's 'FCMT' resource ID from
  943. **    the file or folders fdComment (frComment) field.
  944. */
  945. static    OSErr    GetCommentID(short vRefNum,
  946.                              long dirID,
  947.                              StringPtr name,
  948.                              short *commentID)
  949. {
  950.     CInfoPBRec pb;
  951.     OSErr error;
  952.  
  953.     pb.hFileInfo.ioNamePtr = name;
  954.     pb.hFileInfo.ioVRefNum = vRefNum;
  955.     pb.hFileInfo.ioDirID = dirID;
  956.     pb.hFileInfo.ioFDirIndex = 0;    /* use ioNamePtr and ioDirID */
  957.     error = PBGetCatInfoSync(&pb);
  958.     *commentID = pb.hFileInfo.ioFlXFndrInfo.fdComment;
  959.     return ( error );
  960. }
  961.  
  962. /*****************************************************************************/
  963.  
  964. /*
  965. **    GetCommentFromDesktopFile
  966. **
  967. **    Get a file or directory's Finder comment field (if any) from the
  968. **    Desktop file's 'FCMT' resources.
  969. */
  970. static    OSErr    GetCommentFromDesktopFile(short vRefNum,
  971.                                           long dirID,
  972.                                           StringPtr name,
  973.                                           Str255 comment)
  974. {
  975.     OSErr error;
  976.     short commentID;
  977.     short realVRefNum;
  978.     Str255 desktopName;
  979.     short savedResFile;
  980.     short dfRefNum;
  981.     StringHandle commentHandle;
  982.     
  983.     /* Get the comment ID number */
  984.     error = GetCommentID(vRefNum, dirID, name, &commentID);
  985.     if ( error == noErr )
  986.     {
  987.         if ( commentID != 0 )    /* commentID == 0 means there's no comment */
  988.         {
  989.             error = DetermineVRefNum(name, vRefNum, &realVRefNum);
  990.             if ( error == noErr )
  991.             {
  992.                 error = GetDesktopFileName(realVRefNum, desktopName);
  993.                 if ( error == noErr )
  994.                 {
  995.                     savedResFile = CurResFile();
  996.                     /*
  997.                     **    Open the 'Desktop' file in the root directory. (because
  998.                     **    opening the resource file could preload unwanted resources,
  999.                     **    bracket the call with SetResLoad(s))
  1000.                     */
  1001.                     SetResLoad(false);
  1002.                     dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm);
  1003.                     SetResLoad(true);
  1004.                     
  1005.                     if ( dfRefNum != -1)
  1006.                     {
  1007.                         /* Get the comment resource */
  1008.                         commentHandle = (StringHandle)Get1Resource(kFCMTResType,commentID);
  1009.                         if ( commentHandle != NULL )
  1010.                         {
  1011.                             if ( GetHandleSize((Handle)commentHandle) > 0 )
  1012.                                 BlockMoveData(*commentHandle, comment, *commentHandle[0] + 1);
  1013.                             else
  1014.                                 error = afpItemNotFound;    /* no comment available */
  1015.                         }
  1016.                         else
  1017.                             error = afpItemNotFound;    /* no comment available */
  1018.                         
  1019.                         /* restore the resource chain and close the Desktop file */
  1020.                         UseResFile(savedResFile);
  1021.                         CloseResFile(dfRefNum);
  1022.                     }
  1023.                     else
  1024.                         error = ResError();
  1025.                 }
  1026.             }
  1027.         }
  1028.         else
  1029.             error = afpItemNotFound;    /* no comment available */
  1030.     }
  1031.     
  1032.     return ( error );
  1033. }
  1034.  
  1035. /*****************************************************************************/
  1036.  
  1037. pascal    OSErr    DTGetComment(short vRefNum,
  1038.                              long dirID,
  1039.                              StringPtr name,
  1040.                              Str255 comment)
  1041. {
  1042.     DTPBRec pb;
  1043.     OSErr error;
  1044.     short dtRefNum;
  1045.     Boolean newDTDatabase;
  1046.  
  1047.     if (comment != NULL)
  1048.     {
  1049.         comment[0] = 0;    /* return nothing by default */
  1050.         
  1051.         /* attempt to open the desktop database */
  1052.         error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
  1053.         if ( error == noErr )
  1054.         {
  1055.             /* There was a desktop database and it's now open */
  1056.             
  1057.             if ( !newDTDatabase )
  1058.             {
  1059.                 pb.ioDTRefNum = dtRefNum;
  1060.                 pb.ioNamePtr = name;
  1061.                 pb.ioDirID = dirID;
  1062.                 pb.ioDTBuffer = (Ptr)&comment[1];
  1063.                 error = PBDTGetCommentSync(&pb);
  1064.                 if (error == noErr)
  1065.                     comment[0] = (unsigned char)pb.ioDTActCount;
  1066.             }
  1067.         }
  1068.         else
  1069.         {
  1070.             /* There is no desktop database - try the Desktop file */
  1071.             error = GetCommentFromDesktopFile(vRefNum, dirID, name, comment);
  1072.         }
  1073.     }
  1074.     else
  1075.         error = paramErr;
  1076.     
  1077.     return (error);
  1078. }
  1079.  
  1080. /*****************************************************************************/
  1081.  
  1082. pascal    OSErr    FSpDTGetComment(const FSSpec *spec,
  1083.                               Str255 comment)
  1084. {
  1085.     return (DTGetComment(spec->vRefNum, spec->parID, (StringPtr)spec->name, comment));
  1086. }
  1087.  
  1088. /*****************************************************************************/
  1089.  
  1090. pascal    OSErr    DTCopyComment(short srcVRefNum,
  1091.                               long srcDirID,
  1092.                               StringPtr srcName,
  1093.                               short dstVRefNum,
  1094.                               long dstDirID,
  1095.                               StringPtr dstName)
  1096. /* The destination volume must support the Desktop Manager for this to work */
  1097. {
  1098.     OSErr error;
  1099.     Str255 comment;
  1100.  
  1101.     error = DTGetComment(srcVRefNum, srcDirID, srcName, comment);
  1102.     if ( (error == noErr) && (comment[0] > 0) )
  1103.     {
  1104.         error = DTSetComment(dstVRefNum, dstDirID, dstName, comment);
  1105.     }
  1106.     return (error);
  1107. }
  1108.  
  1109. /*****************************************************************************/
  1110.  
  1111. pascal    OSErr    FSpDTCopyComment(const FSSpec *srcSpec,
  1112.                                const FSSpec *dstSpec)
  1113. /* The destination volume must support the Desktop Manager for this to work */
  1114. {
  1115.     return (DTCopyComment(srcSpec->vRefNum, srcSpec->parID, (StringPtr)srcSpec->name,
  1116.                         dstSpec->vRefNum, dstSpec->parID, (StringPtr)dstSpec->name));
  1117. }
  1118.  
  1119. /*****************************************************************************/
  1120.